{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "e5850a2d-e8fa-4f0c-9bb3-2b4c3d1591c1",
   "metadata": {},
   "source": [
    "# Build Wind Turbine with SageMaker"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "3632d7b3-abf2-4c3b-8709-10b4865df53e",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Collecting s3fs\n",
      "  Using cached s3fs-2024.6.1-py3-none-any.whl.metadata (1.6 kB)\n",
      "Requirement already satisfied: aiobotocore<3.0.0,>=2.5.4 in /opt/conda/lib/python3.10/site-packages (from s3fs) (2.13.1)\n",
      "Collecting fsspec==2024.6.1.* (from s3fs)\n",
      "  Using cached fsspec-2024.6.1-py3-none-any.whl.metadata (11 kB)\n",
      "Requirement already satisfied: aiohttp!=4.0.0a0,!=4.0.0a1 in /opt/conda/lib/python3.10/site-packages (from s3fs) (3.9.5)\n",
      "Requirement already satisfied: botocore<1.34.132,>=1.34.70 in /opt/conda/lib/python3.10/site-packages (from aiobotocore<3.0.0,>=2.5.4->s3fs) (1.34.131)\n",
      "Requirement already satisfied: wrapt<2.0.0,>=1.10.10 in /opt/conda/lib/python3.10/site-packages (from aiobotocore<3.0.0,>=2.5.4->s3fs) (1.14.1)\n",
      "Requirement already satisfied: aioitertools<1.0.0,>=0.5.1 in /opt/conda/lib/python3.10/site-packages (from aiobotocore<3.0.0,>=2.5.4->s3fs) (0.11.0)\n",
      "Requirement already satisfied: aiosignal>=1.1.2 in /opt/conda/lib/python3.10/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->s3fs) (1.3.1)\n",
      "Requirement already satisfied: attrs>=17.3.0 in /opt/conda/lib/python3.10/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->s3fs) (23.2.0)\n",
      "Requirement already satisfied: frozenlist>=1.1.1 in /opt/conda/lib/python3.10/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->s3fs) (1.4.1)\n",
      "Requirement already satisfied: multidict<7.0,>=4.5 in /opt/conda/lib/python3.10/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->s3fs) (6.0.5)\n",
      "Requirement already satisfied: yarl<2.0,>=1.0 in /opt/conda/lib/python3.10/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->s3fs) (1.9.4)\n",
      "Requirement already satisfied: async-timeout<5.0,>=4.0 in /opt/conda/lib/python3.10/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->s3fs) (4.0.3)\n",
      "Requirement already satisfied: jmespath<2.0.0,>=0.7.1 in /opt/conda/lib/python3.10/site-packages (from botocore<1.34.132,>=1.34.70->aiobotocore<3.0.0,>=2.5.4->s3fs) (1.0.1)\n",
      "Requirement already satisfied: python-dateutil<3.0.0,>=2.1 in /opt/conda/lib/python3.10/site-packages (from botocore<1.34.132,>=1.34.70->aiobotocore<3.0.0,>=2.5.4->s3fs) (2.9.0)\n",
      "Requirement already satisfied: urllib3!=2.2.0,<3,>=1.25.4 in /opt/conda/lib/python3.10/site-packages (from botocore<1.34.132,>=1.34.70->aiobotocore<3.0.0,>=2.5.4->s3fs) (1.26.19)\n",
      "Requirement already satisfied: idna>=2.0 in /opt/conda/lib/python3.10/site-packages (from yarl<2.0,>=1.0->aiohttp!=4.0.0a0,!=4.0.0a1->s3fs) (3.7)\n",
      "Requirement already satisfied: six>=1.5 in /opt/conda/lib/python3.10/site-packages (from python-dateutil<3.0.0,>=2.1->botocore<1.34.132,>=1.34.70->aiobotocore<3.0.0,>=2.5.4->s3fs) (1.16.0)\n",
      "Using cached s3fs-2024.6.1-py3-none-any.whl (29 kB)\n",
      "Using cached fsspec-2024.6.1-py3-none-any.whl (177 kB)\n",
      "Installing collected packages: fsspec, s3fs\n",
      "  Attempting uninstall: fsspec\n",
      "    Found existing installation: fsspec 2023.6.0\n",
      "    Uninstalling fsspec-2023.6.0:\n",
      "      Successfully uninstalled fsspec-2023.6.0\n",
      "\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n",
      "datasets 2.20.0 requires fsspec[http]<=2024.5.0,>=2023.1.0, but you have fsspec 2024.6.1 which is incompatible.\n",
      "jupyter-scheduler 2.7.1 requires fsspec==2023.6.0, but you have fsspec 2024.6.1 which is incompatible.\u001b[0m\u001b[31m\n",
      "\u001b[0mSuccessfully installed fsspec-2023.6.0 s3fs-2024.6.1\n",
      "Note: you may need to restart the kernel to use updated packages.\n"
     ]
    }
   ],
   "source": [
    "%pip install s3fs "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "8d27d2ad-bbd6-4944-a217-eaa5758c18d1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Axes: >"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "\n",
    "input_data = \"s3://iiotbook-data/wind_turbine.csv\"\n",
    "df = pd.read_csv(input_data)\n",
    "df.iloc[0:30].plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "e8e5152f-774d-4242-8c3e-b0d0dbb42b3f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.9397263117088558\n"
     ]
    }
   ],
   "source": [
    "import pandas as pd\n",
    "from sklearn.ensemble import GradientBoostingRegressor\n",
    "from sklearn.metrics import r2_score\n",
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "n_estimators=100\n",
    "\n",
    "#Split train and test datasets\n",
    "train_df, test_df = train_test_split(\n",
    "    df,\n",
    "    test_size=0.3,\n",
    ")\n",
    "\n",
    "# build X,y and train,test datasets \n",
    "y_train = train_df.pop(\"power_generated_kw\")\n",
    "X_train = train_df.values\n",
    "y_test = test_df.pop(\"power_generated_kw\")\n",
    "X_test = test_df.values\n",
    "\n",
    "# build the model\n",
    "reg = GradientBoostingRegressor(\n",
    "    n_estimators=n_estimators\n",
    ")\n",
    "reg.fit(X_train, y_train)\n",
    "\n",
    "# test the model\n",
    "y_pred = reg.predict(X_test)\n",
    "\n",
    "print(r2_score(y_test, y_pred))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "d694c2a7-7bec-4312-aec2-49a217e4b5cd",
   "metadata": {},
   "outputs": [],
   "source": [
    "PREFIX = \"wind-turbine\"\n",
    "WORK_DIRECTORY = \"data\"\n",
    "\n",
    "import sagemaker,os\n",
    "\n",
    "sagemaker_session = sagemaker.Session()\n",
    "\n",
    "os.makedirs(WORK_DIRECTORY, exist_ok=True)\n",
    "df.to_csv(\"{}/{}.csv\".format(WORK_DIRECTORY, PREFIX), index=False)\n",
    "\n",
    "train_input = sagemaker_session.upload_data(\n",
    "    WORK_DIRECTORY, key_prefix=\"{}/{}\".format(PREFIX, WORK_DIRECTORY)\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "2d8edbb7-6931-45d0-bd07-d6d7eb83c2dc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Overwriting wind_turbine.py\n"
     ]
    }
   ],
   "source": [
    "%%writefile wind_turbine.py\n",
    "from __future__ import print_function\n",
    "\n",
    "import argparse\n",
    "import joblib\n",
    "import os\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "\n",
    "from sklearn.ensemble import GradientBoostingRegressor\n",
    "from sklearn.metrics import r2_score\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    parser = argparse.ArgumentParser()\n",
    "\n",
    "    # Hyperparameters are described here. In this simple example we are just including one hyperparameter.\n",
    "    parser.add_argument('--n-estimators', type=int, default=-1)\n",
    "\n",
    "    # Sagemaker specific arguments. Defaults are set in the environment variables.\n",
    "    parser.add_argument('--output-data-dir', type=str, default=os.environ['SM_OUTPUT_DATA_DIR'])\n",
    "    parser.add_argument('--model-dir', type=str, default=os.environ['SM_MODEL_DIR'])\n",
    "    parser.add_argument('--train', type=str, default=os.environ['SM_CHANNEL_TRAIN'])\n",
    "\n",
    "    args = parser.parse_args()\n",
    "\n",
    "    # Take the set of files and read them all into a single pandas dataframe\n",
    "    input_files = [ os.path.join(args.train, file) for file in os.listdir(args.train) if file.endswith(\".csv\") ]\n",
    "    print(input_files)\n",
    "    if len(input_files) == 0:\n",
    "        raise ValueError(('There are no files in {}.\\n' +\n",
    "                          'This usually indicates that the channel ({}) was incorrectly specified,\\n' +\n",
    "                          'the data specification in S3 was incorrectly specified or the role specified\\n' +\n",
    "                          'does not have permission to access the data.').format(args.train, \"train\"))\n",
    "    raw_data = [ pd.read_csv(file, engine=\"python\") for file in input_files ]\n",
    "    train_df = pd.concat(raw_data)\n",
    "\n",
    "    y_train = train_df.pop(\"power_generated_kw\")\n",
    "    X_train = train_df.values\n",
    "\n",
    "    # build the model\n",
    "    reg = GradientBoostingRegressor(\n",
    "        n_estimators=args.n_estimators\n",
    "    )\n",
    "    reg.fit(X_train, y_train)\n",
    "\n",
    "    # Print the coefficients of the trained classifier, and save the coefficients\n",
    "    joblib.dump(reg, os.path.join(args.model_dir, \"model.joblib\"))\n",
    "\n",
    "\n",
    "def model_fn(model_dir):\n",
    "    \"\"\"Deserialized and return fitted model\n",
    "    \n",
    "    Note that this should have the same name as the serialized model in the main method\n",
    "    \"\"\"\n",
    "    model = joblib.load(os.path.join(model_dir, \"model.joblib\"))\n",
    "    return model\n",
    "\n",
    "def predict_fn(input_data, model):\n",
    "\n",
    "    if len(input_data.shape) <2:\n",
    "        input_data = input_data.reshape(-1,1)\n",
    "    \n",
    "    prediction = model.predict(input_data)\n",
    "    return np.array(prediction)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "e60e47be-939e-4357-82c6-31015278de3b",
   "metadata": {},
   "outputs": [],
   "source": [
    "from sagemaker.sklearn.estimator import SKLearn\n",
    "from sagemaker import get_execution_role\n",
    "\n",
    "role = get_execution_role()\n",
    "\n",
    "FRAMEWORK_VERSION = \"1.2-1\"\n",
    "script_path = \"wind_turbine.py\"\n",
    "\n",
    "sklearn = SKLearn(\n",
    "    entry_point=script_path,\n",
    "    framework_version=FRAMEWORK_VERSION,\n",
    "    instance_type=\"ml.c4.xlarge\",\n",
    "    role=role,\n",
    "    sagemaker_session=sagemaker_session,\n",
    "    hyperparameters={\"n-estimators\": 100},\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bf0d9e2a-23cd-4223-9254-ef69a7bb3e76",
   "metadata": {},
   "source": [
    "## Train SKLearn Estimator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4433c5bf-3ae6-4b87-9864-8f8f4d8bea9e",
   "metadata": {},
   "outputs": [],
   "source": [
    "sklearn.fit({\"train\": train_input})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9a083631-b579-420f-99e4-3dc53f36a199",
   "metadata": {},
   "source": [
    "## Deploy the model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2a3145c7-f877-4b14-b67e-bc12f60dd6a3",
   "metadata": {},
   "outputs": [],
   "source": [
    "predictor = sklearn.deploy(initial_instance_count=1, instance_type=\"ml.m5.xlarge\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "284d5cb2-e0fd-465f-b1ca-ade7b21ceb62",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([89.59522204, 67.88331554, 72.57244909, ..., 72.57244909,\n",
       "       28.46291311, 43.59427434])"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "predictor.predict(X_test)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6ce6a2ce-d389-463c-b0b4-66f51eedc0a7",
   "metadata": {},
   "source": [
    "## Clean Endpoint"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fe2fb74b-8674-425b-9bfe-a99d4c760ec9",
   "metadata": {},
   "outputs": [],
   "source": [
    "predictor.delete_endpoint()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "352d5132-06fc-4463-ac42-602fa5e3ee70",
   "metadata": {},
   "source": [
    "## MLFLow support"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "15e75c0f-4285-47be-9de1-4fb74a9705eb",
   "metadata": {},
   "outputs": [],
   "source": [
    "from sagemaker.sklearn.estimator import SKLearn\n",
    "from sagemaker import get_execution_role\n",
    "\n",
    "role = get_execution_role()\n",
    "\n",
    "FRAMEWORK_VERSION = \"1.2-1\"\n",
    "script_path = \"wind_turbine.py\"\n",
    "\n",
    "sklearn_mlflow = SKLearn(\n",
    "    entry_point=script_path,\n",
    "    framework_version=FRAMEWORK_VERSION,\n",
    "    instance_type=\"ml.c4.xlarge\",\n",
    "    role=role,\n",
    "    sagemaker_session=sagemaker_session,\n",
    "    hyperparameters={\"n-estimators\": 100},\n",
    "    source_dir=\"src\", \n",
    "    environment={\"MLFLOW_TRACKING_ARN\": \"\"} \n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "7f4abec0-b742-4b15-aec1-84412c03336b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Overwriting src/wind_turbine.py\n"
     ]
    }
   ],
   "source": [
    "%%writefile src/wind_turbine.py\n",
    "from __future__ import print_function\n",
    "\n",
    "import argparse\n",
    "import joblib\n",
    "import os, mflow\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "\n",
    "from sklearn.ensemble import GradientBoostingRegressor\n",
    "from sklearn.metrics import r2_score\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    parser = argparse.ArgumentParser()\n",
    "\n",
    "    # Hyperparameters are described here. In this simple example we are just including one hyperparameter.\n",
    "    parser.add_argument('--n-estimators', type=int, default=-1)\n",
    "\n",
    "    # Sagemaker specific arguments. Defaults are set in the environment variables.\n",
    "    parser.add_argument('--output-data-dir', type=str, default=os.environ['SM_OUTPUT_DATA_DIR'])\n",
    "    parser.add_argument('--model-dir', type=str, default=os.environ['SM_MODEL_DIR'])\n",
    "    parser.add_argument('--train', type=str, default=os.environ['SM_CHANNEL_TRAIN'])\n",
    "\n",
    "    args = parser.parse_args()\n",
    "\n",
    "    # Take the set of files and read them all into a single pandas dataframe\n",
    "    input_files = [ os.path.join(args.train, file) for file in os.listdir(args.train) if file.endswith(\".csv\") ]\n",
    "    print(input_files)\n",
    "    if len(input_files) == 0:\n",
    "        raise ValueError(('There are no files in {}.\\n' +\n",
    "                          'This usually indicates that the channel ({}) was incorrectly specified,\\n' +\n",
    "                          'the data specification in S3 was incorrectly specified or the role specified\\n' +\n",
    "                          'does not have permission to access the data.').format(args.train, \"train\"))\n",
    "    raw_data = [ pd.read_csv(file, engine=\"python\") for file in input_files ]\n",
    "    train_df = pd.concat(raw_data)\n",
    "\n",
    "    mlflow.set_tracking_uri(os.environ['MLFLOW_TRACKING_ARN'])\n",
    "    mlflow.autolog()\n",
    "\n",
    "    y_train = train_df.pop(\"power_generated_kw\")\n",
    "    X_train = train_df.values\n",
    "\n",
    "    # build the model\n",
    "    reg = GradientBoostingRegressor(\n",
    "        n_estimators=args.n_estimators\n",
    "    )\n",
    "    reg.fit(X_train, y_train)\n",
    "\n",
    "    # Print the coefficients of the trained classifier, and save the coefficients\n",
    "    joblib.dump(reg, os.path.join(args.model_dir, \"model.joblib\"))\n",
    "\n",
    "\n",
    "def model_fn(model_dir):\n",
    "    \"\"\"Deserialized and return fitted model\n",
    "    \n",
    "    Note that this should have the same name as the serialized model in the main method\n",
    "    \"\"\"\n",
    "    model = joblib.load(os.path.join(model_dir, \"model.joblib\"))\n",
    "    return model\n",
    "\n",
    "def predict_fn(input_data, model):\n",
    "\n",
    "    if len(input_data.shape) <2:\n",
    "        input_data = input_data.reshape(-1,1)\n",
    "    \n",
    "    prediction = model.predict(input_data)\n",
    "    return np.array(prediction)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "ea8bbecf-69f8-441c-b508-e546309c3786",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Overwriting src/requirements.txt\n"
     ]
    }
   ],
   "source": [
    "%%writefile src/requirements.txt \n",
    "mlflow==2.13.2 \n",
    "sagemaker-mlflow==0.1.0 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bfd8642e-4222-4d59-8597-9298fa70afb6",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:sagemaker:Creating training-job with name: sagemaker-scikit-learn-2024-08-31-20-33-14-977\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2024-08-31 20:33:16 Starting - Starting the training job.."
     ]
    }
   ],
   "source": [
    "sklearn_mlflow.fit({\"train\": train_input})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "17a0219a-7bff-4f10-911a-8fb3f2293b20",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
